package com.ymsoft.myerp.socketio;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.ymsoft.myerp.entity.User;
import com.ymsoft.myerp.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service(value = "socketIOService")
public class SocketIOServiceImpl implements SocketIOService {
    private static final Logger _log = LoggerFactory.getLogger(SocketIOServiceImpl.class);

    // 用来存已连接的客户端
    private static Map<String, SocketIOClient> clientMap = new ConcurrentHashMap<>();

    @Autowired
    private SocketIOServer socketIOServer;

    @Autowired
    private IUserService iUserService;

    /**
     * Spring IoC容器创建之后，在加载SocketIOServiceImpl Bean之后启动
     *
     * @throws Exception
     */
    @PostConstruct
    private void autoStartup() throws Exception {
        start();
    }

    /**
     * Spring IoC容器在销毁SocketIOServiceImpl Bean之前关闭,避免重启项目服务端口占用问题
     *
     * @throws Exception
     */
    @PreDestroy
    private void autoStop() throws Exception {
        stop();
    }

    @Override
    public void start() {
        // 监听客户端连接
        socketIOServer.addConnectListener(client -> {
            User user = getParamsByClient(client);
            if (user != null) {
                String username = user.getUsername();
                SocketIOClient oldClient = clientMap.get(username);
                if (null == oldClient) {
                    clientMap.put(username, client);
                } else {
                    clientMap.remove(username);
                    oldClient.disconnect();
                    clientMap.put(username, client);
                }
            } else {
                client.disconnect();
            }
        });
        // 监听客户端断开连接
        socketIOServer.addDisconnectListener(client -> {
            User user = getParamsByClient(client);
            if (user != null) {
                clientMap.remove(user.getUsername());
                client.disconnect();
            }
        });

        // 处理自定义的事件，与连接监听类似
        socketIOServer.addEventListener(RECEIVE, PushMessage.class, (client, data, ackSender) -> {
            // TODO do something
            // 前端传回消息
            System.out.println(data.getContent() + "---" + data.getUsername());

        });

        socketIOServer.start();
    }

    @Override
    public void stop() {
        if (socketIOServer != null) {
            socketIOServer.stop();
            socketIOServer = null;
        }
    }

    /**
     * 断开连接
     *
     * @param username
     */
    @Override
    public void disconnect(String username) {
        SocketIOClient client = clientMap.get(username);
        if (client != null)
            client.disconnect();
    }

    @Override
    public void pushMessageToUser(PushMessage pushMessage) {
        String username = pushMessage.getUsername().toString();
        SocketIOClient client = clientMap.get(username);
        if (client != null)
            client.sendEvent(RECEIVE, pushMessage);
    }

    @Override
    public void pushMessageToUser(String username, String content, String event) {
        _log.info("推送用户：" + username);
        SocketIOClient client = clientMap.get(username);
        if (client != null)
            client.sendEvent(event, content);
        _log.info("socket断开：" + username);
    }

    /**
     * 此方法为获取client连接中的参数，可根据需求更改
     *
     * @param client
     * @return
     */
    private User getParamsByClient(SocketIOClient client) {
        // 从请求的连接中拿出参数（这里的loginUserNum必须是唯一标识）
        Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
        List<String> list = params.get("token");
        if (list != null && list.size() > 0) {
            String token = list.get(0);
            return iUserService.getUserByToken(null, token);
        }
        return null;
    }

    /**
     * 获取当前列表
     * @return
     */
    @Override
    public Map<String, SocketIOClient> getMaps(){
        return this.clientMap;
    }
}